package com.example.demokotlin

import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Test
import kotlin.reflect.KFunction1


/**
 * 基础语法测试
 *
 * @author zhouronghua
 * @time 2021/9/9 8:56 上午
 */
class GrammarTest {
    @Test
    fun addition_isCorrect() {
        assertEquals(4, 2 + 2)
    }

    /**
     * TODO函数
     *  TODO函数的任务就是抛出异常，就是永远别指望它运行成功，返回Nothing类型
     *
     * @author zhouronghua
     * @time 2021/9/9 8:53 上午
     */
    @Test
    fun testNothing() = runBlocking<Unit> {
        // 测试TODO函数
        println("开始测试TODO函数")
        TODO("Nothing")
        println("开始测试TODO函数结束")
    }

    /**
     * 反引号中的函数名
     * 1）Kotlin可以使用空格和特殊字符对函数命名，不过函数名需要使用一对返回引号括起来
     * 2）为了Kotlin和Java互操作，而Kotlin和Java各自有着不同的保留关键字，不能作为函数名，
     * 使用反引号括住函数就能避免命名冲突
     */
    fun `**~special function with world name**runBlocking`(hint: String) = runBlocking {
        println("这个是特殊的runBlocking函数，参数为：$hint")
    }

    @Test
    fun testSpecialFunction() {
        // 通过反引号中的函数名直接引用函数
        `**~special function with world name**runBlocking`("特殊函数")
    }

    /**
     * 匿名函数
     * 匿名函数就是没有函数名的函数
     * 1）匿名函数看起来非常像一个常规函数声明，除了其名称省略了。其函数体可以是表达式（如上所示）或代码块：
     * 2）匿名函数参数总是在括号内传递。 允许将函数留在圆括号外的简写语法仅适用于 lambda 表达式。
     *
     * @author zhouronghua
     * @time 2021/9/10 8:30 上午
     */
    @Test
    fun testAnonymous() {
        // mySum是一个函数引用，将一个一个匿名函数赋值给他
        val mySum = { i: Int, b: Int -> i + b }
        val a = 5
        val b = 8
        println("a + b = ${mySum(a, b)}")
    }

    /**
     * 函数声明
     * 输入参数：括号内定义
     * 返回值：Stirng类型，箭头执行返回值类型
     * 函数体：大括号定义函数体
     *
     * @author zhouronghua
     * @time 2021/9/27 7:40 下午
     */
    fun configDiscountWords(): (String) -> String {
        val currentYear = 2027
        val hour = (1 .. 24).shuffled().last()
        return { goodsName: String ->
            "$currentYear 年，双十一${goodsName}促销倒计时 $hour 小时"
        }
    }

    /**
     * 获取商品打折信息
     *
     * @author zhouronghua
     * @time 2021/9/27 7:54 下午
     */
    private fun getDiscountWords(): (String, Int) -> String {
        val currentYear = 2027
        return { goodsName: String, hour: Int ->
            "$currentYear 年，双十一${goodsName}促销倒计时 $hour 小时"
        }
    }

    /**
     * 公告板显示商品打折信息
     *
     * @author zhouronghua
     * @time 2021/9/27 7:55 下午
     */
    private fun showOnBoard(goodsName: String, getDiscountWords: (String, Int) -> String) {
        val hour = (1 .. 24).shuffled().first()
        println(getDiscountWords(goodsName, hour))
    }

    /**
     * 测试函数返回值
     * 说明: 吹风机双十一促销倒计时
     *
     * @author zhouronghua
     * @time 2021/9/27 7:45 下午
     */
    @Test
    fun testFunReturn() {
        println("=== 测试函数作为返回值 ===")
        val funGetDiscountWords = configDiscountWords()
        println(funGetDiscountWords("吹风机"))
    }

    /**
     * 匿名函数引用着自身函数里的变量，kotlin中lambda就是闭包
     * 高阶函数：能够接受函数参数或者返回函数的函数就叫高阶函数。
     * 高阶函数广泛用于函数变成当中。
     *
     * @author zhouronghua
     * @time 2021/9/27 7:49 下午
     */
    @Test
    fun testLambda() {
        println("=== 测试高阶函数 ===")
        // 子函数引用直接使用getDiscountWords()
        println(showOnBoard("白酒", getDiscountWords()))
    }
}